/* ------------------------------------------
 * Copyright (c) 2016, Synopsys, Inc. All rights reserved.

 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:

 * 1) Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.

 * 2) Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation and/or
 * other materials provided with the distribution.

 * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may
 * be used to endorse or promote products derived from this software without
 * specific prior written permission.

 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * \version 2016.05
 * \date 2014-07-15
 * \author Wayne Ren(Wei.Ren@synopsys.com)
--------------------------------------------- */

/**
 * \file
 * \ingroup ARC_HAL_STARTUP
 * \brief assembly part of startup process
 */

/**
 * \addtogroup ARC_HAL_STARTUP
 * @{
 */
/** @cond STARTUP_ASM */

#define __ASSEMBLY__
#include "embARC_BSP_config.h"
#include "inc/arc/arc.h"

.file "arc_startup.S"

.weak   _f_sdata        /* start of small data, defined in link script */
.weak   init_hardware_hook  /* app hardware init hook */
.weak   init_software_hook  /* app software init hook */

.extern board_main
.extern exc_entry_table

/* initial vector table */
.section .init_vector, "a"
.long _arc_reset
.section .init_bootstrap, "ax"
.global _arc_reset
.global _start
.align 4
_start:
_arc_reset:
_arc_reset_stage1:
kflag   STATUS32_RESET_VALUE

/* STAGE 1 */

/* necessary hardware should be done first to speed up initialization
    1. system clk
    2. mem controller must be initialized before any access to external
    mem.
    3. others
*/
_arc_cache_init_start:
lr  r0, [AUX_BCR_D_CACHE]
cmp r0, 2
/* invalidate dcache */
jle _arc_icache_init
mov r0, 1
sr  r0, [AUX_DC_IVDC]
sr  r0, [AUX_DC_CTRL]
_arc_icache_init:
lr  r0, [AUX_BCR_I_CACHE]
cmp r0, 2
jle _arc_cache_init_end
/* invalidate icache */
mov r0, 1
sr  r0, [AUX_IC_IVIC]
nop_s
nop_s
nop_s
sr  r0, [AUX_IC_CTRL]

_arc_cache_init_end:
mov r0, init_hardware_hook
cmp r0, 0
jlne    [r0]

/* STAGE 2: init necessary registers */

_arc_reset_stage2:
mov r0, 0

/* interrupt related init */
sr  r0, [AUX_IRQ_ACT]
sr  r0, [AUX_IRQ_CTRL]
sr  r0, [AUX_IRQ_HINT]

/* use the new vector table to replace the old one */
#if defined(ARC_FEATURE_SEC_PRESENT) && (SECURESHIELD_VERSION < 2)
sr  exc_entry_table, [AUX_INT_VECT_BASE_S]
#else
sr  exc_entry_table, [AUX_INT_VECT_BASE]
#endif

/* init stack */
#if ARC_FEATURE_RGF_BANKED_REGS >= 16 && ARC_FEATURE_RGF_BANKED_REGS > 1 && ARC_FEATURE_FIRQ == 1
#if _STACKSIZE < 512
#error "not enough stack size for irq and firq"
#endif

/* switch to register bank1 */
lr      r0, [AUX_STATUS32]
bic     r0, r0, 0x70000
or      r0, r0, 0x10000
kflag   r0
/* set sp, gp, fp in bank1 */
mov     sp, _e_stack
mov     gp, _f_sdata
mov     fp, 0
/* come back to bank0 */
lr      r0, [AUX_STATUS32]
bic     r0, r0, 0x70000
kflag   r0
mov sp, _e_stack - 256
#else
mov sp, _e_stack    /* init stack pointer */
#endif
mov gp, _f_sdata    /* init small-data base register */
mov fp, 0       /* init fp register */

_arc_reset_stage3:
_s3_copy_text:
mov r0, _f_text
mov r1, _load_addr_text
cmp r0, r1

/* if load addr == run addr, no need to copy */
jeq _s3_copy_rodata
mov r3, _e_text
_s3_copy_text_loop:
ld.ab   r2, [r1, 4]
st.ab   r2, [r0, 4]
cmp r0, r3
jlt _s3_copy_text_loop
_s3_copy_rodata:
mov r0, _f_rodata
mov r1, _load_addr_rodata
cmp r0, r1

/* if load addr == run addr, no need to copy */
jeq _s3_copy_data
mov r3, _e_rodata
_s3_copy_rodata_loop:
ld.ab   r2, [r1, 4]
st.ab   r2, [r0, 4]
cmp r0, r3
jlt _s3_copy_rodata_loop
_s3_copy_data:
mov r0, _f_data
mov r1, _load_addr_data
cmp r0, r1
jeq _s3_clear_bss

/* if load addr == run addr, no need to copy */
mov r3, _e_data
_s3_copy_data_loop:
ld.ab   r2, [r1, 4]
st.ab   r2, [r0, 4]
cmp r0, r3
jlt _s3_copy_data_loop
_s3_clear_bss:
mov r0, _f_bss
mov r1, _e_bss
cmp r0, r1
jge _arc_reset_call_main
mov r2, 0
_s3_clear_bss_loop:
st.ab   r2, [r0, 4]
cmp r0, r1
jlt _s3_clear_bss_loop

/* STAGE 3: go to main */

_arc_reset_call_main:

/* \todo add cpp init here */
mov r0, init_software_hook
cmp r0, 0
jlne    [r0]
/* board level library init */
#ifdef  LIB_SECURESHIELD
jl  secureshield_start
#else
/* early init of interrupt and exception */
jl  exc_int_init
#endif
/* init cache */
jl  arc_cache_init
#if defined(__MW__)
jl  _init
#elif defined(__GNU__)
jl  __do_global_ctors_aux
jl  __do_init_array_aux
#endif
jl  board_main  /* board-level main */
#if defined(__MW__)
jl  _fini
#elif defined(__GNU__)
jl  __do_global_dtors_aux
#endif
.global _exit_loop
.global _exit_halt
.align 4
_exit_halt:
_exit_loop:
flag    0x1
nop
nop
nop
b   _exit_loop

#if defined(__MW__)
.global _init, _fini
.section ".init", text
_init:
.cfa_bf _init
push    % blink
.cfa_push   { % blink}

.section ".init$999999", text, 1, 2, check_text_align = 0
                                                        pop % blink
                                                        .cfa_pop    { % blink}
                                                        j   [ % blink]
                                                        .cfa_ef

                                                        .section ".fini", text
                                                        _fini:
                                                        .cfa_bf _fini
                                                        push    % blink
                                                        .cfa_push   { % blink}

                                                        .section ".fini$999999", text, 1, 2, check_text_align = 0
                                                                pop % blink
                                                                .cfa_pop    { % blink}
                                                                j   [ % blink]
                                                                .cfa_ef
#endif
                                                                /** @endcond */

                                                                /** }@*/
